# Copyright (C) 2007 Lemur Consulting Ltd
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""Monkeypatches to fix bugs in twisted.

MonkeyPatches aren't usually a good idea, so they should be well documented,
reported to upstream, and removed when upstream fixes the issue they are
intended to resolve.


Currently, this file contains the following patches:

1. Patch twisted.web.server.Request so that, if notifyFinish is called when the
   request has already finished due to the connection being lost, the
   resulting deferred's errback() will be called as soon as it is set.

"""


from twisted.web import server
orig_server_request_init = server.Request.__init__
def fixed_server_request_init(self, *args, **kwargs):
    """A version of twisted.web.server.Request.connectionLost which adds a
    _connection_lost member.

    """
    orig_server_request_init(self, *args, **kwargs)
    self._connection_lost = None
server.Request.__init__ = fixed_server_request_init

orig_server_request_connectionLost = server.Request.connectionLost
def fixed_server_request_connectionLost(self, reason):
    """A version of twisted.web.server.Request.connectionLost which takes note
    of a connection lost message, and makes a note of it, so that future calls
    to notifyFinish can call the errback on the deferred immediately.

    """
    orig_server_request_connectionLost(self, reason)
    self._connection_lost = reason
server.Request.connectionLost = fixed_server_request_connectionLost

orig_server_request_notifyFinish = server.Request.notifyFinish
def fixed_server_request_notifyFinish(self):
    """A version of twisted.web.server.Request.notifyFinish which calls the
    errback callback immediately if the connection has already been lost.

    """
    deferred = orig_server_request_notifyFinish(self)
    if self._connection_lost is not None:
        self.connectionLost(self._connection_lost)
    return deferred
server.Request.notifyFinish = fixed_server_request_notifyFinish
